﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

using System.IO;
using System.Xml;
using System.Xml.Serialization;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Storage;

namespace Spacer {
	/// <summary>
	/// INTERNAL USE
	/// Used in conjuction with XmlObjectCfg to load and save data in Xml documents.
	/// </summary>
	public class SettingsCfg {
		public string ContentPath { get; set; }
		public bool Fullscreen { get; set; }
		public int ResolutionWidth { get; set; }
		public int ResolutionHeight { get; set; }
		public int FSResolutionWidth { get; set; }
		public int FSResolutionHeight { get; set; }
		public SerializableDictionary<int,string> Bindings { get; set; }

		// -----------

		public SettingsCfg() {
			ContentPath = "Content";

			#if !XBOX360
			Fullscreen = false;
			#else
			Fullscreen = true;
			#endif
			
			ResolutionWidth = 1280;
			ResolutionHeight = 800;
			FSResolutionWidth = 1680;
			FSResolutionHeight = 1050;
			Bindings = new SerializableDictionary<int,string>();
		}
	}

	// ----------------------------------------------------------------------------------------------------

	public static class Configuration {
		public static string Filename { get; private set; }
		private static SettingsCfg Settings { get; set; }

		// ----------

		public static string ContentPath {
			get { return Settings.ContentPath; }
			set { Settings.ContentPath = value; }
		}

		public static bool Fullscreen {
			get { return Settings.Fullscreen; }
			set { Settings.Fullscreen = value; }
		}

		public static int ResolutionWidth {
			get { return Settings.ResolutionWidth; }
			set { Settings.ResolutionWidth = value; }
		}

		public static int ResolutionHeight {
			get { return Settings.ResolutionHeight; }
			set { Settings.ResolutionHeight = value; }
		}

		public static int FSResolutionWidth {
			get { return Settings.FSResolutionWidth; }
			set { Settings.FSResolutionWidth = value; }
		}

		public static int FSResolutionHeight {
			get { return Settings.FSResolutionHeight; }
			set { Settings.FSResolutionHeight = value; }
		}

		public static SerializableDictionary<int,string> Bindings {
			get { return Settings.Bindings; }
			set { Settings.Bindings = value; }
		}

		// ----------

		public static void Initialize() {
			Filename = "Settings.xml";
			Settings = new SettingsCfg();

			//Load();
		}

		public static void Load() {
			Settings = XmlObjectCfg<SettingsCfg>.Load( Filename );
			if( Settings == null ) {
				Settings = new SettingsCfg();
				Save();
			}
		}

		public static void Save() {
			XmlObjectCfg<SettingsCfg>.Save( Settings, Filename );
		}
	}
	
	// ----------------------------------------------------------------------------------------------------

	public static class XmlObjectCfg<T> where T : new() {
		private static XmlSerializer m_XmlSerializer = Initialize();

		// ----------

		public static Type SerializedType {
			get { return typeof( T ); }
		}

		// ----------

		private static XmlSerializer Initialize() {
			m_XmlSerializer = new XmlSerializer( typeof(T) );
			return m_XmlSerializer;
		}

		/// <summary>
		/// Opens a file FROM USER STORAGE as an Xml document and deserializes it into the requested object.
		/// </summary>
		/// <param name="filename">The path to the file requested.</param>
		/// <returns>Requested object on success, otherwise null.</returns>
		public static T Load( string filename ) { if( Globals.LocalStorage != null ) return Load(filename,Globals.LocalStorage); return default(T); }
		/// <summary>
		/// Opens a file as an Xml document and deserializes it into the requested object.
		/// </summary>
		/// <param name="filename">The path to the file requested.</param>
		/// <param name="container">Optional - If null, the search path is the game title container. If a StorageContainer is provided it will be searched instead.</param>
		/// <returns>Requested object on success, otherwise null.</returns>
		public static T Load( string filename, StorageContainer container ) {
			T ret = default( T );
			Stream stream = null;
			XmlReader reader = null;

			try {
				if( container == null )
					stream = TitleContainer.OpenStream( filename );
				else if( container.StorageDevice.IsConnected )
					stream = container.OpenFile( filename, FileMode.Open, FileAccess.Read, FileShare.Read );

				if( stream != null && stream.CanRead ) {
					reader = XmlReader.Create( stream );
					if( reader != null ) {
						ret = (T)m_XmlSerializer.Deserialize( reader );
						reader.Close();
					}
					stream.Close();
				}
			} catch( Exception e ) {
				if( reader != null )
					reader.Close();
				if( stream != null )
					stream.Close();

				Console.WriteLine( e.Message );
			}

			return ret;
		}
		
		/// <summary>
		/// Serializes an object and saves it to a file IN USER STORAGE as an Xml document.
		/// </summary>
		/// <param name="obj">The object to serialize.</param>
		/// <param name="filename">The path to save to.</param>
		public static void Save( Object obj, string filename ) { if( Globals.LocalStorage != null ) Save(obj,filename,Globals.LocalStorage); }
		/// <summary>
		/// Serializes an object and saves it to a file as an Xml document.
		/// </summary>
		/// <param name="obj">The object to serialize.</param>
		/// <param name="filename">The path to save to.</param>
		public static void Save( Object obj, string filename, StorageContainer container ) {
			Stream stream = null;
			XmlWriter writer = null;
			
			try {
				XmlWriterSettings writerSettings = new XmlWriterSettings();
				#if DEBUG
				writerSettings.Indent = true;
				writerSettings.IndentChars = "\t";
				writerSettings.NewLineChars = "\r\n";
				#endif

				if( container == null )
					throw new ArgumentNullException( "container" );
				else if( container.StorageDevice.IsConnected )
					stream = container.OpenFile( filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None );

				if( stream != null && stream.CanWrite ) {
					writer = XmlWriter.Create( stream, writerSettings );
					if( writer != null ) {
						m_XmlSerializer.Serialize( writer, obj );
						writer.Close();
					}
					stream.Close();
				}
			} catch( Exception e ) {
				if( writer != null )
					writer.Close();
				if( stream != null )
					stream.Close();

				Console.WriteLine( e.Message );
			}
		}

		// ----------

		public static string SerializeToString( Object obj ) {
			StringBuilder strbuilder = new StringBuilder();
			XmlWriter writer = null;
			
			try {
				XmlWriterSettings writerSettings = new XmlWriterSettings();
				#if DEBUG
				writerSettings.Indent = true;
				writerSettings.IndentChars = "\t";
				writerSettings.NewLineChars = "\r\n";
				#endif

				if( strbuilder != null ) {
					writer = XmlWriter.Create( strbuilder, writerSettings );
					if( writer != null ) {
						m_XmlSerializer.Serialize( writer, obj );
						writer.Close();
					}
				}
			} catch( Exception e ) {
				if( writer != null )
					writer.Close();

				Console.WriteLine( e.Message );
			}

			return strbuilder.ToString();
		}

		public static T DeserializeFromString( string data ) {
			T ret = default( T );
			StringReader strreader = new StringReader( data );
			XmlReader reader = null;

			try {
				if( strreader != null ) {
					reader = XmlReader.Create( strreader );
					if( reader != null ) {
						ret = (T)m_XmlSerializer.Deserialize( reader );
						reader.Close();
					}
					strreader.Close();
				}
			} catch( Exception e ) {
				if( reader != null )
					reader.Close();
				if( strreader != null )
					strreader.Close();

				Console.WriteLine( e.Message );
			}

			return ret;
		}
	}
}
